import json
import logging
import httpx
import random
from typing import Optional, Dict, Any
from tortoise.exceptions import DoesNotExist
from src.config.settings import get_settings
from src.utils.logger import app_logger as logger
import jwt
from src.models.user import User
from src.schemas.user import (
    UserLoginRequest,
    UserInfo,
    UpdateUserRequest,
    LoginResponse,
)
from src.services.file_service import FileService
from fastapi import UploadFile
from src.utils.auth import create_access_token
from datetime import datetime, timedelta


class UserService:
    """用户服务"""

    @staticmethod
    async def login_with_wechat(code: str) -> LoginResponse:
        """微信登录"""
        try:
            # 调用微信API获取用户信息
            wechat_user_info = await UserService._get_wechat_user_info(code)

            # 准备用户默认数据
            from src.config.settings import get_settings
            settings = get_settings()
            defaults = {
                "nickname": UserService._generate_default_nickname(),
                "avatar": settings.DEFAULT_AVATAR_URL,
                "points": 0  # 新用户默认积分
            }
            
            # 如果微信返回了手机号，则使用微信的手机号
            if wechat_user_info.get("phone"):
                defaults["phone"] = wechat_user_info["phone"]

            # 查找或创建用户
            user, created = await User.get_or_create(
                openid=wechat_user_info["openid"], defaults=defaults
            )

            # 如果用户已存在，只更新手机号（如果微信返回了新的手机号）
            if not created:
                updated = False
                if (
                    wechat_user_info.get("phone")
                    and wechat_user_info["phone"] != user.phone
                ):
                    user.phone = wechat_user_info["phone"]
                    updated = True

                if updated:
                    await user.save()

            # 生成JWT token对（access token + refresh token）
            from src.services.refresh_token_service import RefreshTokenService
            
            token_data = await RefreshTokenService.create_token_pair(
                user_id=user.id,
                username=user.nickname or f"用户{user.id}"
            )

            # 构造用户信息
            user_info = UserInfo.model_validate(user)

            logger.info(f"用户登录成功: {user.id}")
            return LoginResponse(
                access_token=token_data["access_token"],
                refresh_token=token_data["refresh_token"],
                token_type=token_data["token_type"],
                expires_in=token_data["expires_in"],
                user_info=user_info
            )

        except Exception as e:
            logger.error(f"微信登录失败: {str(e)}")
            raise Exception(f"登录失败: {str(e)}")

    @staticmethod
    async def _get_wechat_user_info(code: str) -> Dict[str, Any]:
        """获取微信用户信息"""
        # 微信小程序配置
        app_id = "wx8d5d4b018ccd3ce3"
        app_secret = "fa6bf836d309f1ddd7cd5ac8d5a2da98"

        # 获取access_token
        token_url = f"https://api.weixin.qq.com/sns/jscode2session"
        params = {
            "appid": app_id,
            "secret": app_secret,
            "js_code": code,
            "grant_type": "authorization_code",
        }

        async with httpx.AsyncClient() as client:
            response = await client.get(token_url, params=params)
            data = response.json()

            if "errcode" in data:
                raise Exception(f"微信API错误: {data.get('errmsg', '未知错误')}")

            # 构建返回数据，只包含有效字段
            result = {"openid": data["openid"], "session_key": data.get("session_key")}

            # 只有在微信API返回了这些字段时才添加
            # 注意：小程序的jscode2session接口不会返回用户信息
            # 需要用户主动授权后通过其他方式获取
            if "nickname" in data and data["nickname"]:
                result["nickname"] = data["nickname"]
            if "headimgurl" in data and data["headimgurl"]:
                result["avatar"] = data["headimgurl"]
            if "phone" in data and data["phone"]:
                result["phone"] = data["phone"]

            return result

    @staticmethod
    def _generate_default_nickname() -> str:
        """生成默认昵称：鹅吻天使#随机数字"""
        random_number = random.randint(100000, 999999)
        return f"鹅吻天使#{random_number}"

    @staticmethod
    def _generate_token(user_id: int) -> str:
        """生成JWT token"""
        # 使用auth.py中的create_access_token函数确保格式一致
        return create_access_token(data={"user_id": user_id})

    @staticmethod
    async def get_user_profile(user_id: int) -> UserInfo:
        """获取用户信息"""
        try:
            user = await User.get(id=user_id)
            
            # 如果用户昵称或头像为空，自动填充默认值并保存
            updated = False
            if not user.nickname:
                user.nickname = UserService._generate_default_nickname()
                updated = True
            # 检查头像是否为空或者是旧的本地路径，如果是则更新为新的网络地址
            from src.config.settings import get_settings
            settings = get_settings()
            if not user.avatar or user.avatar in ["static/images/usagi.png", "/static/images/usagi.png", "https://wuyonglong-oss.oss-cn-shanghai.aliyuncs.com/ewentianshi/avatar/usagi.png"]:
                user.avatar = settings.DEFAULT_AVATAR_URL
                updated = True
                
            if updated:
                await user.save()
                logger.info(f"用户 {user_id} 默认信息已更新")
            
            # 创建用户信息对象
            user_info = UserInfo.model_validate(user)
            
            # 如果头像是OSS URL，重新生成7天有效期的签名URL
            if user_info.avatar and ("oss-cn-" in user_info.avatar or "aliyuncs.com" in user_info.avatar):
                file_service = FileService()
                user_info.avatar = file_service.regenerate_signed_url_from_url(user_info.avatar)
                logger.info(f"用户 {user_id} 头像URL已重新生成签名")
            
            return user_info
        except DoesNotExist:
            raise Exception("用户不存在")

    @staticmethod
    async def update_user_profile(
        user_id: int, update_data: UpdateUserRequest
    ) -> UserInfo:
        """更新用户信息"""
        try:
            user = await User.get(id=user_id)

            # 更新昵称
            if update_data.nickname is not None:
                user.nickname = update_data.nickname

            # 更新头像
            if update_data.avatar is not None:
                user.avatar = update_data.avatar

            await user.save()

            logger.info(f"用户 {user_id} 信息更新成功")
            return UserInfo.model_validate(user)

        except DoesNotExist:
            raise Exception("用户不存在")
        except Exception as e:
            logger.error(f"更新用户信息失败: {str(e)}")
            raise Exception(f"更新用户信息失败: {str(e)}")

    @staticmethod
    async def upload_avatar(user_id: int, avatar_file: UploadFile) -> UserInfo:
        """上传用户头像到OSS并更新用户信息"""
        try:
            user = await User.get(id=user_id)

            # 创建文件服务实例
            file_service = FileService()

            # 上传头像到OSS的avatar目录
            upload_result = await file_service.upload_to_oss(
                user_id=user_id,
                image_file=avatar_file,
                storage_path=file_service.OSS_AVATAR_PATH,
            )

            # 更新用户头像URL
            user.avatar = upload_result.image_url
            await user.save()

            logger.info(f"用户 {user_id} 头像上传成功: {upload_result.image_url}")
            
            # 创建用户信息对象并重新生成头像签名URL
            user_info = UserInfo.model_validate(user)
            if user_info.avatar and ("oss-cn-" in user_info.avatar or "aliyuncs.com" in user_info.avatar):
                user_info.avatar = file_service.regenerate_signed_url_from_url(user_info.avatar)
            
            return user_info

        except DoesNotExist:
            raise Exception("用户不存在")
        except Exception as e:
            logger.error(f"头像上传失败: {str(e)}")
            raise Exception(f"头像上传失败: {str(e)}")
